/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package pabudr_se;



import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriter;
import javax.imageio.stream.MemoryCacheImageOutputStream;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.filechooser.FileNameExtensionFilter;


class FileIO {
    public static final boolean DEBUG = DebugStatus.DEBUG;

    // FileChooser zur Bildspeicherung und Settingsspeicherung
    private final JFileChooser imgJFC, setJFC;
    // Marker fuer eine Settings Datei
    private final static Integer FILE_IDENTIFIER = 0x4701DE;
    private HashMap<ImageWriter, ArrayList<String>> imgWriterList;

    class ImageFilter extends javax.swing.filechooser.FileFilter
    {
        ArrayList<String> extlist;
        ImageWriter iwriter;
        ImageFilter(ImageWriter iwriter, ArrayList<String> list)
        {
            extlist = list;
            this.iwriter = iwriter;
        }
        @Override
        public boolean accept(File f) {
            if (f.isDirectory()) return true;
            String filename = f.getName();
            boolean ret = false;
            for (String ext : extlist)
            {
                if (filename.lastIndexOf(ext) != -1)
                {
                    ret = true;
                    break;
                }
            }
            return ret;
        }

        @Override
        public String getDescription() {
            return iwriter.getClass().getSimpleName();
        }

    }

    FileIO() 
    {
        imgJFC = new JFileChooser();
        imgJFC.setFileSelectionMode(JFileChooser.FILES_ONLY);

        setJFC = new JFileChooser();
        setJFC.setFileSelectionMode(JFileChooser.FILES_ONLY);

        imgWriterList = new HashMap<ImageWriter, ArrayList<String>>();
        for (String name : ImageIO.getWriterFormatNames())
        {
            ImageIO.getImageWritersByFormatName(name);
            for (Iterator<ImageWriter> it = ImageIO.getImageWritersByFormatName(name);
            it.hasNext(); )
            {
                ImageWriter imgWriter = it.next();
                boolean add = true;
                final Class thisClass = imgWriter.getClass();
                ImageWriter inList = null;
                for (ImageWriter imWriteInList : imgWriterList.keySet())
                {
                    final Class ListClass = imWriteInList.getClass();
                    if (thisClass.equals(ListClass))
                    {
                        add = false;
                        inList = imWriteInList;
                        break;
                    }
                }
                if (add)
                {
                    ArrayList<String> tmpList = new ArrayList<String>();
                    tmpList.add(name);
                    imgWriterList.put(imgWriter, tmpList);
                }
                else
                {
                    ArrayList<String> tmpList = imgWriterList.get(inList);
                    tmpList.add(name);
                }
            }
        }
        //entferne den Standart FileFilter der alle Dateien akzeptiert
        imgJFC.removeChoosableFileFilter(imgJFC.getAcceptAllFileFilter());
        setJFC.removeChoosableFileFilter(setJFC.getAcceptAllFileFilter());

        // FileFilter fuer Bilddateien hinzufuegen
        for (ImageWriter im : imgWriterList.keySet())
        {
            imgJFC.addChoosableFileFilter(
                    new ImageFilter(im, imgWriterList.get(im)
                    ));
        }
        if (DEBUG)
        {
            for (ImageWriter im : imgWriterList.keySet())
            {
                System.out.print(im);
                for (String ext : imgWriterList.get(im))
                {
                    System.out.print(' ' + ext);
                }
                System.out.println();
            }
        } // End "if(DEBUG)"

       //FileFilter fuer Settings hinzufuegen
       setJFC.addChoosableFileFilter(new FileNameExtensionFilter("Settings file", "set"));

    }

    boolean saveImage(BufferedImage image)
    {
        if(DEBUG)
        {
            System.out.println("saveImage");
       
        }
        //Titel ändern
        imgJFC.setDialogTitle("Choose File to write Image");
        //Button Text ändern
        imgJFC.setApproveButtonText("Save");
        //Chooser anzeigen
        int userOption = imgJFC.showOpenDialog(null);

        //return wenn kein file gewählt, z.b.: wenn auf abbrechen gedrückt wurde
        if( imgJFC.getSelectedFile() == null ) return false;

        //User fragen wenn datei vorhanden
        handleExistingFile(imgJFC);
        
        //Hole den Filter
        ImageFilter filter;
        try {
            filter = (ImageFilter)imgJFC.getFileFilter();
        }
        catch (ClassCastException e) {
            if (DEBUG)
                System.out.println("Fehler beim Casten des FileFilters!");
            return false;
        }
        File file = imgJFC.getSelectedFile();
        if(DEBUG)
        {
            System.out.println("Selected File =\t"+file);
            System.out.println(filter.iwriter.toString());
        }

        ImageWriter iwriter = filter.iwriter;

        try {
            iwriter.setOutput(new MemoryCacheImageOutputStream(new FileOutputStream(file)));
            if (DEBUG) System.out.println("writing image");
            iwriter.write(image);
            if (DEBUG) System.out.println("image written");
        } catch (FileNotFoundException e) {
            System.out.println("Datei nicht gefunden!");
        } catch (IOException ex) {
            Logger.getLogger(FileIO.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            //iwriter.reset();
            iwriter.dispose();
            file = null;
        }
        return true;
            
    }


  

    /**
     *
     * @param settings - zu schreibende Einstellungen
     * @return Status des Schreibvorgangs
     * @throws FileNotFoundException
     * @throws IOException
     */
    boolean saveSettings(Settings settings) throws FileNotFoundException, IOException
    {
        if(DEBUG)
        {
            System.out.println("saveSettings");
            System.out.println("Selected File =\t"+setJFC.getSelectedFile());
        }

        //Titel ändern
        setJFC.setDialogTitle("Choose File to write Settings");
        //Button Text ändern
        setJFC.setApproveButtonText("Save");
        //Chooser anzeigen
        setJFC.showOpenDialog(null);
        
        if(DEBUG)
        {
            System.out.println("Selected File =\t"+setJFC.getSelectedFile());
        }
        //return wenn kein file gewählt, z.b.: wenn auf abbrechen gedrückt wurde
        if( setJFC.getSelectedFile() == null ) return false;
        
        //User fragen wenn datei vorhanden
        handleExistingFile(setJFC);

        //Output Streams
        final FileOutputStream fos = new FileOutputStream(setJFC.getSelectedFile());
        final ObjectOutputStream oos = new ObjectOutputStream(fos);

        //Settings in File schreiben
        try
        {
            // Erkennungsflag am Dateianfang setzen
            oos.writeObject(FILE_IDENTIFIER);
            // Einstellungen schreiben
            oos.writeObject(settings);
            oos.close();
            return true;
        } catch (IOException ex) {
            Logger.getLogger(FileIO.class.getName()).log(Level.SEVERE, null, ex);
        }
        return false;
    }
    /**
     *
     * @return Settings aus der gewählten Datei oder null falls keine enthalten sind
     * @throws IOException
     * @throws ClassNotFoundException
     */
    Settings loadSettings(/*File file*/)
    {
        if(DEBUG)
        {
            System.out.println("read Settings");
            System.out.println("Selected File =\t"+setJFC.getSelectedFile());
        }

        //Titel ändern
        setJFC.setDialogTitle("Select File with Settings");
        //Button Text ändern
        setJFC.setApproveButtonText("use settings");
        //Chooser anzeigen
        setJFC.showOpenDialog(null);

        if(DEBUG)
        {
            System.out.println("Selected File =\t"+setJFC.getSelectedFile());
        }

        //wenn kein file gewählt, z.b. bei abbruch
        if( setJFC.getSelectedFile() == null ) return null;

        //wenn file nicht existiert erneut fragen
        while( !setJFC.getSelectedFile().exists() )
        {
            final int swp;
            swp =JOptionPane.showConfirmDialog(setJFC, "File does not exist.\nChoose another one?");
            //swp = 1 wenn user nein gewählt hat
            //swp = 0 wenn user ja gewählt hat
            //bei nein methode verlassen ==> nichts zu lesen
            //bei ja erneut nachfragen
            if( swp == 1) return null;
            else setJFC.showOpenDialog(null);

        }

        // nachfragen ob user sicher
        // da laufende sim ueberschrieben wird
        
        Object settings = null;
        boolean loop = true;
        // Stream muss nach finden der Eiingabedatei veruegbar sein
        ObjectInputStream ois = null;
        // settingsflag des aktuellen files
        Integer fi = null;

        // Bis Eingabedaei Settings enthaelt oder user abbricht
        do
        {
            try
            {
                    //Input Streams
                final FileInputStream fis = new FileInputStream(setJFC.getSelectedFile());
                ois = new ObjectInputStream(fis);
                fi = (Integer)ois.readObject();
            }catch (IOException ex) {
                Logger.getLogger(FileIO.class.getName()).log(Level.SEVERE, null, ex);
            }catch(ClassNotFoundException e)
            {
                Logger.getLogger(FileIO.class.getName()).log(Level.SEVERE, null, e);
            }

            // Datei ist EingabeDatei
            if( fi.equals(FILE_IDENTIFIER ) )
            {
                // Flag to exit loop
                loop = false;
            } // End "if( fi.equals(FILE_IDENTIFIER ) )"
            else
            {

                if( JOptionPane.showConfirmDialog(setJFC, "File contains no simulation settings.\nChoose another one?") == 0)
                {
                    // Benutzer moechte neue Datei waehlen
                    // schleife wiederholen
                    continue;
                }else
                {
                    //keine neue Datei waehlen
                    // exit loop
                    loop = false;
                }
            } // End "else if ( fi.equals(FILE_IDENTIFIER ) )"
            
        }while( loop );
        
        // settings lesen
        try {
            settings = ois.readObject();
            ois.close();
        } catch (IOException ex) {
            Logger.getLogger(FileIO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (ClassNotFoundException ex) {
            Logger.getLogger(FileIO.class.getName()).log(Level.SEVERE, null, ex);
        }
        
        return ( settings instanceof Settings ) ? (Settings)settings : null;
    }

      private void handleExistingFile(final JFileChooser jFC)
    {
        while( jFC.getSelectedFile().exists() )
        {
            //User hat überschreiben gewählt ==> Schleife verlassen (optPane return 0)
            if( JOptionPane.showConfirmDialog(jFC, "File exists. Do you want to override it?") == 0)
                break;
            //User hat nein gewählt, neues File wählen (optPane return 1)
            else
                jFC.showOpenDialog(null);
            
            
        }
    }

}
